package com.example.JavaWebApi.service.impl.systemImpl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.AopUtils;
import com.example.JavaWebApi.mapper.systemMapper.ApiRoleMapper;
import com.example.JavaWebApi.model.entity.systemEntity.ApiRole;
import com.example.JavaWebApi.model.vo.systemVo.ApiRoleVo;
import com.example.JavaWebApi.model.vo.systemVo.ControllerDescription;
import com.example.JavaWebApi.service.systemService.IApiRoleService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ApiRoleServiceImpl extends ServiceImpl<ApiRoleMapper, ApiRole> implements IApiRoleService {
    @Autowired
    private ApplicationContext applicationContext;
    private static List<ControllerDescription> cache;
    @Override
    public List<ControllerDescription> getList() {
        if(cache==null){
            HashMap<String,ControllerDescription> descriptionHashMap=new HashMap<>();
            RequestMappingHandlerMapping mapping= applicationContext.getBean(RequestMappingHandlerMapping.class);
            Map<RequestMappingInfo, HandlerMethod> map= mapping.getHandlerMethods();
            for(Map.Entry<RequestMappingInfo, HandlerMethod> entry: map.entrySet()){
                RequestMappingInfo info = entry.getKey();
                HandlerMethod method = entry.getValue();
                Class<?> beanClass = method.getBeanType();
                ControllerDescription controllerDescription;
                if(descriptionHashMap.containsKey(beanClass.getName())){
                    controllerDescription=descriptionHashMap.get(beanClass.getName());
                }else {
                    controllerDescription=new ControllerDescription();
                    controllerDescription.setName(beanClass.getName());
                    Api api = beanClass.getAnnotation(Api.class);
                    RequestMapping requestMapping= beanClass.getAnnotation(RequestMapping.class);
                    controllerDescription.setApiDescriptionList(new ArrayList<>());
                    controllerDescription.setMapping(String.join(";",requestMapping.value()));
                    if(api!=null){
                        controllerDescription.setDescription(String.join(";",api.tags()));
                    }

                    descriptionHashMap.put(beanClass.getName(),controllerDescription);
                }
                ControllerDescription.ApiDescription apiDescription=new ControllerDescription.ApiDescription();
                apiDescription.setName(method.getMethod().getName());
                ApiOperation apiOperation=method.getMethodAnnotation(ApiOperation.class);
                if (apiOperation != null) {
                    apiDescription.setDescription(apiOperation.value());
                }
                apiDescription.setMethod(info.getMethodsCondition().getMethods().stream().map(Enum::toString).collect(Collectors.joining(";")));
                apiDescription.setParent(beanClass.getName());
                if (info.getPatternsCondition() != null) {
                    apiDescription.setMapping(info.getPatternsCondition().toString());
                }
                controllerDescription.getApiDescriptionList().add(apiDescription);
            }
            cache=new ArrayList<>(descriptionHashMap.values());
        }
        return cache;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean save(ApiRoleVo vo) {
        LambdaUpdateWrapper<ApiRole> updateWrapper=new LambdaUpdateWrapper<>();
        updateWrapper.eq(ApiRole::getRoleId,vo.getMainId());
        baseMapper.delete(updateWrapper);
        if(!vo.getSubIds().isEmpty()){
            List<ApiRole> apiRoles=new ArrayList<>();
            for (String id : vo.getSubIds()){
                ApiRole apiRole=new ApiRole();
                apiRole.setApiId(id);
                apiRole.setRoleId(vo.getMainId());
                apiRoles.add(apiRole);
            }
            saveBatch(apiRoles);
        }

        return true;
    }

    @Override
    public List<String> getRoleApi(List<Integer> roleIds,List<String> apiIds) {
        LambdaQueryWrapper<ApiRole> queryWrapper=new LambdaQueryWrapper<>();
        queryWrapper.in(ApiRole::getRoleId,roleIds)
                .in(apiIds!=null && !apiIds.isEmpty(),ApiRole::getApiId,apiIds)
                .select(ApiRole::getApiId);
        List<ApiRole> apiRoles=list(queryWrapper);
        return apiRoles.stream().map(ApiRole::getApiId).collect(Collectors.toList());
    }
}
